Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #207 +/- ##
==========================================
+ Coverage 98.12% 98.24% +0.12%
==========================================
Files 32 32
Lines 3353 3365 +12
==========================================
+ Hits 3290 3306 +16
+ Misses 63 59 -4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Benchmark Results (minimum time) — macos-14Reporting the minimum over all samples (robust to shared-runner contention), not the median. Alternative backends vs Float32 (
|
| Scenario | F32 | I16 | 1b | 2b | ×I16 | ×1b | ×2b |
|---|---|---|---|---|---|---|---|
| 4-antenna @ 5 MHz | 11.8 μs | 6.24 μs | 4.7 μs | 9.75 μs | 1.9 ✅ | 2.52 ✅ | 1.21 ✅ |
| GPS L1CA, 8 sats @ 40 MHz | 369.0 μs | 117.0 μs | 57.2 μs | 109.0 μs | 3.15 ✅ | 6.44 ✅ | 3.39 ✅ |
| GPS L1CA, 8 sats @ 5 MHz, 100 ms buffer | 5.06 ms | 1.87 ms | 1.19 ms | 1.94 ms | 2.71 ✅ | 4.27 ✅ | 2.61 ✅ |
| GPS L1CA, 8 sats @ 5 MHz | 53.8 μs | 21.6 μs | 15.5 μs | 24.4 μs | 2.49 ✅ | 3.47 ✅ | 2.2 ✅ |
| Galileo E1B, 4 sats @ 25 MHz | 142.0 μs | 59.5 μs | 2.38 ✅ | ||||
| dynamic taps @ 5 MHz (kernel) | 6.68 μs | 2.28 μs | 1.49 μs | 2.55 μs | 2.93 ✅ | 4.48 ✅ | 2.62 ✅ |
| multi-signal N=3 @ 5 MHz | 11.2 μs | 5.31 μs | 4.47 μs | 7.17 μs | 2.12 ✅ | 2.52 ✅ | 1.57 ✅ |
Time benchmarks (base vs PR head)
Ratio = 8f3b080… / aeea0e2…: >1 means the PR is faster. ✅ ≥ 5 % faster,
| 8f3b080… | aeea0e2… | 8f3b080… / aeea0e2… | |
|---|---|---|---|
| downconvert and correlate/CPU/Float32 | 2.71 μs | 2.53 μs | 1.07 ✅ |
| downconvert and correlate/CPU/Float32 4ant | 5.29 μs | 4.93 μs | 1.07 ✅ |
| downconvert and correlate/CPU/Float64 | 2.95 μs | 2.73 μs | 1.08 ✅ |
| downconvert and correlate/CPU/Int16 | 2.87 μs | 2.67 μs | 1.07 ✅ |
| downconvert and correlate/CPU/Int16 4ant | 5.24 μs | 4.88 μs | 1.07 ✅ |
| downconvert and correlate/CPU/Int32 | 2.68 μs | 2.58 μs | 1.04 |
| fused kernel/1-ant dynamic taps | 2.57 μs | 2.56 μs | 1.01 |
| fused kernel/1-ant static taps | 2.06 μs | 2.06 μs | 1.0 |
| fused kernel/4-ant dynamic taps | 7.81 μs | 7.78 μs | 1.0 |
| fused kernel/4-ant static taps | 4.43 μs | 4.43 μs | 1.0 |
| fused tuple kernel/1-ant N=2 | 3.39 μs | 3.27 μs | 1.04 |
| fused tuple kernel/1-ant N=3 | 3.41 μs | 3.4 μs | 1.0 |
| fused tuple kernel/2-ant N=2 | 6.32 μs | 6.31 μs | 1.0 |
| fused tuple kernel/2-ant N=3 | 5.82 μs | 5.62 μs | 1.04 |
| fused tuple kernel/4-ant N=2 | 12.0 μs | 11.5 μs | 1.04 |
| fused tuple kernel/4-ant N=3 | 10.1 μs | 10.1 μs | 1.0 |
| track/1. Float32/2K – track | 2.94 μs | 2.83 μs | 1.04 |
| track/1. Float32/2K – track! | 3.11 μs | 2.94 μs | 1.06 ✅ |
| track/2. L1 8sat/5K – track | 54.8 μs | 51.1 μs | 1.07 ✅ |
| track/2. L1 8sat/5K – track! | 54.5 μs | 50.9 μs | 1.07 ✅ |
| track/2. L1 8sat/5K – track! Int16 | 22.3 μs | 23.9 μs | 0.932 |
| track/2. L1 8sat/5K – track! OneBit | 17.2 μs | 17.1 μs | 1.0 |
| track/2. L1 8sat/5K – track!-threaded | 52.6 μs | 52.6 μs | 0.999 |
| track/2. L1 8sat/5K – track-threaded | 51.0 μs | 51.0 μs | 0.999 |
| track/3. E1B 4sat/25K – track | 136.0 μs | 136.0 μs | 1.0 |
| track/3. E1B 4sat/25K – track! | 136.0 μs | 136.0 μs | 1.0 |
| track/3. E1B 4sat/25K – track! Int16 | 58.9 μs | 59.2 μs | 0.994 |
| track/3. E1B 4sat/25K – track!-threaded | 141.0 μs | 146.0 μs | 0.965 |
| track/3. E1B 4sat/25K – track-threaded | 137.0 μs | 147.0 μs | 0.932 |
| track/4. 8L1+8E1B/25K – track | 492.0 μs | 527.0 μs | 0.933 |
| track/4. 8L1+8E1B/25K – track! | 490.0 μs | 490.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track!-threaded | 491.0 μs | 491.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track-threaded | 492.0 μs | 492.0 μs | 1.0 |
| track/5. multi-signal N=1/5K – track | 6.87 μs | 6.62 μs | 1.04 |
| track/5. multi-signal N=1/5K – track! | 7.12 μs | 6.59 μs | 1.08 ✅ |
| track/6. multi-signal N=2/5K – track | 11.5 μs | 10.7 μs | 1.07 ✅ |
| track/6. multi-signal N=2/5K – track! | 11.6 μs | 10.8 μs | 1.08 ✅ |
| track/7. L1 8sat/500K – track! Int16 | 1.91 ms | 1.92 ms | 0.997 |
| track/7. L1 8sat/500K – track! OneBit | 1.23 ms | 1.23 ms | 1.0 |
| track/7. L1 8sat/500K – track! TwoBit | 1.97 ms | 2.14 ms | 0.922 |
| track/7. multi-signal N=3/5K – track | 12.9 μs | 12.0 μs | 1.07 ✅ |
| track/7. multi-signal N=3/5K – track! | 12.1 μs | 13.0 μs | 0.93 |
| track/8. L1CA presync 2 blk – track! | 12.8 μs | 13.7 μs | 0.936 |
| track/8. L1CA presync 20 blk – track! | 127.0 μs | 125.0 μs | 1.02 |
| track/8. L1CA synced 2 blk – track! | 12.7 μs | 12.7 μs | 1.0 |
| track/8. L1CA synced 20 blk – track! | 122.0 μs | 122.0 μs | 1.0 |
| time_to_load | 145.0 μs | 144.0 μs | 1.01 |
Memory benchmarks (base vs PR head)
Ratio = 8f3b080… / aeea0e2… (bytes allocated): >1 means the PR allocates less. ✅ ≥ 5 % less, ∞/0 mark a benchmark that drops to / picks up allocations, — means both revisions allocate nothing. A blank cell means the benchmark exists on only one revision (🆕 = new on the PR, 🗑 = removed).
| 8f3b080… | aeea0e2… | 8f3b080… / aeea0e2… | |
|---|---|---|---|
| downconvert and correlate/CPU/Float32 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Float32 4ant | 2 allocs: 928 B | 2 allocs: 928 B | 1.0 |
| downconvert and correlate/CPU/Float64 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Int16 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Int16 4ant | 2 allocs: 928 B | 2 allocs: 928 B | 1.0 |
| downconvert and correlate/CPU/Int32 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| fused kernel/1-ant dynamic taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/1-ant static taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/4-ant dynamic taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/4-ant static taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/1-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/1-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/2-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/2-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/4-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/4-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/1. Float32/2K – track | 9 allocs: 944 B | 9 allocs: 944 B | 1.0 |
| track/1. Float32/2K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track | 10 allocs: 4656 B | 10 allocs: 4656 B | 1.0 |
| track/2. L1 8sat/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track! Int16 | 13 allocs: 1056 B | 13 allocs: 1056 B | 1.0 |
| track/2. L1 8sat/5K – track! OneBit | 45 allocs: 2736 B | 45 allocs: 2736 B | 1.0 |
| track/2. L1 8sat/5K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track-threaded | 10 allocs: 4656 B | 10 allocs: 4656 B | 1.0 |
| track/3. E1B 4sat/25K – track | 10 allocs: 3056 B | 10 allocs: 3056 B | 1.0 |
| track/3. E1B 4sat/25K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/3. E1B 4sat/25K – track! Int16 | 5 allocs: 416 B | 5 allocs: 416 B | 1.0 |
| track/3. E1B 4sat/25K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/3. E1B 4sat/25K – track-threaded | 10 allocs: 3056 B | 10 allocs: 3056 B | 1.0 |
| track/4. 8L1+8E1B/25K – track | 26 allocs: 10976 B | 26 allocs: 10976 B | 1.0 |
| track/4. 8L1+8E1B/25K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/4. 8L1+8E1B/25K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/4. 8L1+8E1B/25K – track-threaded | 26 allocs: 10976 B | 26 allocs: 10976 B | 1.0 |
| track/5. multi-signal N=1/5K – track | 9 allocs: 944 B | 9 allocs: 944 B | 1.0 |
| track/5. multi-signal N=1/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/6. multi-signal N=2/5K – track | 9 allocs: 1408 B | 9 allocs: 1408 B | 1.0 |
| track/6. multi-signal N=2/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/7. L1 8sat/500K – track! Int16 | 61 allocs: 28704 B | 61 allocs: 28704 B | 1.0 |
| track/7. L1 8sat/500K – track! OneBit | 1677 allocs: 119088 B | 1677 allocs: 119088 B | 1.0 |
| track/7. L1 8sat/500K – track! TwoBit | 1677 allocs: 119136 B | 1677 allocs: 119136 B | 1.0 |
| track/7. multi-signal N=3/5K – track | 9 allocs: 1760 B | 9 allocs: 1760 B | 1.0 |
| track/7. multi-signal N=3/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/8. L1CA presync 2 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA presync 20 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA synced 2 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA synced 20 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| time_to_load | 196 allocs: 13984 B | 196 allocs: 13984 B | 1.0 |
Benchmark Results (minimum time) — ubuntu-latestReporting the minimum over all samples (robust to shared-runner contention), not the median. Alternative backends vs Float32 (
|
| Scenario | F32 | I16 | 1b | 2b | ×I16 | ×1b | ×2b |
|---|---|---|---|---|---|---|---|
| 4-antenna @ 5 MHz | 12.0 μs | 7.48 μs | 5.84 μs | 11.0 μs | 1.61 ✅ | 2.06 ✅ | 1.09 ✅ |
| GPS L1CA, 8 sats @ 40 MHz | 338.0 μs | 139.0 μs | 63.7 μs | 117.0 μs | 2.43 ✅ | 5.31 ✅ | 2.9 ✅ |
| GPS L1CA, 8 sats @ 5 MHz, 100 ms buffer | 4.77 ms | 2.38 ms | 1.48 ms | 2.4 ms | 2.0 ✅ | 3.23 ✅ | 1.99 ✅ |
| GPS L1CA, 8 sats @ 5 MHz | 51.7 μs | 28.4 μs | 19.0 μs | 27.3 μs | 1.82 ✅ | 2.73 ✅ | 1.89 ✅ |
| Galileo E1B, 4 sats @ 25 MHz | 126.0 μs | 60.1 μs | 2.1 ✅ | ||||
| dynamic taps @ 5 MHz (kernel) | 6.35 μs | 3.57 μs | 1.78 μs | 2.67 μs | 1.78 ✅ | 3.56 ✅ | 2.38 ✅ |
| multi-signal N=3 @ 5 MHz | 10.9 μs | 6.49 μs | 5.77 μs | 8.34 μs | 1.67 ✅ | 1.88 ✅ | 1.3 ✅ |
Time benchmarks (base vs PR head)
Ratio = 8f3b080… / aeea0e2…: >1 means the PR is faster. ✅ ≥ 5 % faster,
| 8f3b080… | aeea0e2… | 8f3b080… / aeea0e2… | |
|---|---|---|---|
| downconvert and correlate/CPU/Float32 | 2.43 μs | 2.42 μs | 1.0 |
| downconvert and correlate/CPU/Float32 4ant | 4.47 μs | 4.46 μs | 1.0 |
| downconvert and correlate/CPU/Float64 | 2.81 μs | 2.81 μs | 0.998 |
| downconvert and correlate/CPU/Int16 | 2.53 μs | 2.53 μs | 0.999 |
| downconvert and correlate/CPU/Int16 4ant | 4.91 μs | 4.9 μs | 1.0 |
| downconvert and correlate/CPU/Int32 | 2.46 μs | 2.45 μs | 1.0 |
| fused kernel/1-ant dynamic taps | 2.3 μs | 2.29 μs | 1.0 |
| fused kernel/1-ant static taps | 1.91 μs | 1.92 μs | 0.997 |
| fused kernel/4-ant dynamic taps | 5.56 μs | 5.6 μs | 0.994 |
| fused kernel/4-ant static taps | 3.88 μs | 3.87 μs | 1.0 |
| fused tuple kernel/1-ant N=2 | 2.57 μs | 2.57 μs | 1.0 |
| fused tuple kernel/1-ant N=3 | 3.15 μs | 3.09 μs | 1.02 |
| fused tuple kernel/2-ant N=2 | 3.95 μs | 3.94 μs | 1.0 |
| fused tuple kernel/2-ant N=3 | 5.05 μs | 4.99 μs | 1.01 |
| fused tuple kernel/4-ant N=2 | 6.47 μs | 6.48 μs | 0.999 |
| fused tuple kernel/4-ant N=3 | 10.2 μs | 10.2 μs | 1.0 |
| track/1. Float32/2K – track | 2.81 μs | 2.83 μs | 0.994 |
| track/1. Float32/2K – track! | 2.88 μs | 2.91 μs | 0.992 |
| track/2. L1 8sat/5K – track | 49.7 μs | 49.7 μs | 1.0 |
| track/2. L1 8sat/5K – track! | 48.9 μs | 49.5 μs | 0.987 |
| track/2. L1 8sat/5K – track! Int16 | 28.4 μs | 30.0 μs | 0.948 |
| track/2. L1 8sat/5K – track! OneBit | 19.1 μs | 19.0 μs | 1.0 |
| track/2. L1 8sat/5K – track!-threaded | 49.3 μs | 49.2 μs | 1.0 |
| track/2. L1 8sat/5K – track-threaded | 49.6 μs | 49.8 μs | 0.995 |
| track/3. E1B 4sat/25K – track | 122.0 μs | 122.0 μs | 0.999 |
| track/3. E1B 4sat/25K – track! | 121.0 μs | 121.0 μs | 1.0 |
| track/3. E1B 4sat/25K – track! Int16 | 59.0 μs | 58.9 μs | 1.0 |
| track/3. E1B 4sat/25K – track!-threaded | 122.0 μs | 122.0 μs | 0.999 |
| track/3. E1B 4sat/25K – track-threaded | 122.0 μs | 122.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track | 446.0 μs | 445.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track! | 444.0 μs | 444.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track!-threaded | 444.0 μs | 443.0 μs | 1.0 |
| track/4. 8L1+8E1B/25K – track-threaded | 445.0 μs | 445.0 μs | 1.0 |
| track/5. multi-signal N=1/5K – track | 6.41 μs | 6.4 μs | 1.0 |
| track/5. multi-signal N=1/5K – track! | 6.58 μs | 6.44 μs | 1.02 |
| track/6. multi-signal N=2/5K – track | 9.46 μs | 9.36 μs | 1.01 |
| track/6. multi-signal N=2/5K – track! | 9.64 μs | 9.59 μs | 1.01 |
| track/7. L1 8sat/500K – track! Int16 | 2.35 ms | 2.36 ms | 0.994 |
| track/7. L1 8sat/500K – track! OneBit | 1.45 ms | 1.45 ms | 0.997 |
| track/7. L1 8sat/500K – track! TwoBit | 2.2 ms | 2.44 ms | 0.903 |
| track/7. multi-signal N=3/5K – track | 12.1 μs | 12.2 μs | 0.993 |
| track/7. multi-signal N=3/5K – track! | 12.3 μs | 12.4 μs | 0.992 |
| track/8. L1CA presync 2 blk – track! | 12.0 μs | 12.1 μs | 0.995 |
| track/8. L1CA presync 20 blk – track! | 116.0 μs | 115.0 μs | 1.0 |
| track/8. L1CA synced 2 blk – track! | 11.9 μs | 12.0 μs | 0.995 |
| track/8. L1CA synced 20 blk – track! | 114.0 μs | 114.0 μs | 1.0 |
| time_to_load | 118.0 μs | 115.0 μs | 1.02 |
Memory benchmarks (base vs PR head)
Ratio = 8f3b080… / aeea0e2… (bytes allocated): >1 means the PR allocates less. ✅ ≥ 5 % less, ∞/0 mark a benchmark that drops to / picks up allocations, — means both revisions allocate nothing. A blank cell means the benchmark exists on only one revision (🆕 = new on the PR, 🗑 = removed).
| 8f3b080… | aeea0e2… | 8f3b080… / aeea0e2… | |
|---|---|---|---|
| downconvert and correlate/CPU/Float32 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Float32 4ant | 2 allocs: 928 B | 2 allocs: 928 B | 1.0 |
| downconvert and correlate/CPU/Float64 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Int16 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| downconvert and correlate/CPU/Int16 4ant | 2 allocs: 928 B | 2 allocs: 928 B | 1.0 |
| downconvert and correlate/CPU/Int32 | 2 allocs: 576 B | 2 allocs: 576 B | 1.0 |
| fused kernel/1-ant dynamic taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/1-ant static taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/4-ant dynamic taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused kernel/4-ant static taps | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/1-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/1-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/2-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/2-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/4-ant N=2 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| fused tuple kernel/4-ant N=3 | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/1. Float32/2K – track | 9 allocs: 944 B | 9 allocs: 944 B | 1.0 |
| track/1. Float32/2K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track | 10 allocs: 4664 B | 10 allocs: 4664 B | 1.0 |
| track/2. L1 8sat/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track! Int16 | 13 allocs: 1056 B | 13 allocs: 1056 B | 1.0 |
| track/2. L1 8sat/5K – track! OneBit | 45 allocs: 2736 B | 45 allocs: 2736 B | 1.0 |
| track/2. L1 8sat/5K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/2. L1 8sat/5K – track-threaded | 10 allocs: 4664 B | 10 allocs: 4664 B | 1.0 |
| track/3. E1B 4sat/25K – track | 10 allocs: 2872 B | 10 allocs: 2872 B | 1.0 |
| track/3. E1B 4sat/25K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/3. E1B 4sat/25K – track! Int16 | 5 allocs: 416 B | 5 allocs: 416 B | 1.0 |
| track/3. E1B 4sat/25K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/3. E1B 4sat/25K – track-threaded | 10 allocs: 2872 B | 10 allocs: 2872 B | 1.0 |
| track/4. 8L1+8E1B/25K – track | 26 allocs: 10608 B | 26 allocs: 10608 B | 1.0 |
| track/4. 8L1+8E1B/25K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/4. 8L1+8E1B/25K – track!-threaded | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/4. 8L1+8E1B/25K – track-threaded | 26 allocs: 10608 B | 26 allocs: 10608 B | 1.0 |
| track/5. multi-signal N=1/5K – track | 9 allocs: 944 B | 9 allocs: 944 B | 1.0 |
| track/5. multi-signal N=1/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/6. multi-signal N=2/5K – track | 9 allocs: 1408 B | 9 allocs: 1408 B | 1.0 |
| track/6. multi-signal N=2/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/7. L1 8sat/500K – track! Int16 | 61 allocs: 25696 B | 61 allocs: 25696 B | 1.0 |
| track/7. L1 8sat/500K – track! OneBit | 1677 allocs: 116080 B | 1677 allocs: 116080 B | 1.0 |
| track/7. L1 8sat/500K – track! TwoBit | 1677 allocs: 116128 B | 1677 allocs: 116128 B | 1.0 |
| track/7. multi-signal N=3/5K – track | 9 allocs: 1760 B | 9 allocs: 1760 B | 1.0 |
| track/7. multi-signal N=3/5K – track! | 0 allocs: 0 B | 0 allocs: 0 B | — |
| track/8. L1CA presync 2 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA presync 20 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA synced 2 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| track/8. L1CA synced 20 blk – track! | 7 allocs: 320 B | 7 allocs: 320 B | 1.0 |
| time_to_load | 145 allocs: 11216 B | 145 allocs: 11216 B | 1.0 |
Sanction feeding externally produced `CorrelatorOutput`s (e.g. from an FPGA/hardware correlator) to the Doppler estimator, running only the loop filters on the host. - Decouple `estimate_dopplers_and_filter_prompt(!)` from `BandMeasurements`: both the immutable and in-place `ConventionalPLLAndDLL` methods now accept a per-band sampling-frequency source (a `NamedTuple`/`Dict` keyed by `get_band_id`) as well as `BandMeasurements`. The estimator reads only the per-band rate (via the new `_band_sampling_frequency` helper), so the FPGA path needs no sample buffer. The CPU `track!` path is unchanged and stays allocation-free. - Add `append_correlator_output!` (exported) — the blessed ingest path onto a signal's `correlator_outputs` buffer, at `TrackedSignal`/`TrackedSat`/ `TrackState` addressing levels; add matching `get_correlator_outputs` accessors at the `TrackedSat`/`TrackState` levels. - Document the `sample_index` convention for a free-running global counter, the "estimate consumes and clears the buffer" contract, the caller contract, and the one-epoch transport-delay note under a new "External correlator producers" section (docs/src/track.md), plus the fs-based method in the custom-estimator guide. - Test: exact equivalence between the `BandMeasurements` and fs paths, the Dict/NamedTuple/immutable variants, every append addressing level, and a standalone external-producer estimate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #203.
Sanctions an external correlator producer (e.g. the LiteX M2SDR FPGA) feeding completed correlator dumps to the Doppler estimator, so downconversion + correlation can be offloaded to hardware while only the tracking loop filters run on the host. Builds on the per-chunk
correlator_outputsmechanism from #205.What changed
1. Estimator decoupled from
BandMeasurementsestimate_dopplers_and_filter_prompt/estimate_dopplers_and_filter_prompt!(forConventionalPLLAndDLL, hence also the defaultConventionalAssistedPLLAndDLL) now accept a per-band sampling-frequency source — aNamedTuple/Dictkeyed byband_key— in addition toBandMeasurements. The per-band rate is looked up through a new_band_sampling_frequencyhelper, so the estimator stays per-band (groups may sit on different bands) and needs no sample buffer. TheBandMeasurementsoverload is preserved, so the CPUtrack!path is untouched and remains allocation-free (verified by the in-place per-stage allocation test).2. External-producer ingest path
append_correlator_output!(exported): the blessed way to append an externally builtCorrelatorOutputto a signal's buffer, atTrackedSignal/TrackedSat/TrackStateaddressing levels — cleaner and type-checked versus mutating the vectorget_correlator_outputsreturns.get_correlator_outputsgainsTrackedSat/TrackStateaccessors (per-signal addressing), matching the other accessors.estimate_dopplers_and_filter_prompt!(track_state, fs)standalone over an externally-filled buffer skipsdownconvert_and_correlate!entirely.3.
sample_indexconvention + docsCorrelatorOutput(correlator, integrated_samples, sample_index; code_phase = 0.0)keyword constructor for external producers.docs/src/track.md: the offload loop, the caller contract (raw accumulator scaling, trueintegrated_samples, per-signalsample_indexorder), how a free-running global sample counter maps onto the chunk-relativesample_indexgrid, and the one-epoch transport-delay note. The custom-estimator guide documents the fs-based method.Testing
test/external_correlator_producer.jl: exact equivalence between theBandMeasurementsand fs paths, Dict/NamedTuple/immutable variants, the constructor, everyappend_correlator_output!addressing level, and a standalone external-producer estimate.Pkg.test()passes; docs build cleanly with doctests; JuliaFormatter 2.8.5 clean.Out of scope
DMA/FIFO ingest, transports, wire format, NCO marshaling, hardware channel management — all in GNSSReceiver.jl#107.
🤖 Generated with Claude Code